#include "non_copyable.h"
#include "itcp_server.h"
#include "client.h"

#include <iostream>
#include <signal.h>


class Statistics
  : private tinySrv::NonCopyable
{
public:
  Statistics()
    : ConnectCounter(0)
    , ClosedCounter(0)
    , RecvBytes(0)
  {
  }
  void AddConnectCounter()
  {
    __sync_fetch_and_add(&ConnectCounter, 1);
  }
  void AddCloseCounter()
  {
    __sync_fetch_and_add(&ClosedCounter, 1);
  }
  void AddDataCounter(long bytes)
  {
    __sync_fetch_and_add(&RecvBytes, bytes);
  }
  void ShowStatistics()
  {
    std::cout
        << "Cennected: " << __sync_fetch_and_add(&ConnectCounter, 0) << std::endl
        << "Closed: " << __sync_fetch_and_add(&ClosedCounter, 0) << std::endl
        << "RecvBytes: " << __sync_fetch_and_add(&RecvBytes, 0) << std::endl;
  }
private:
  unsigned long volatile ConnectCounter;
  unsigned long volatile ClosedCounter;
  unsigned long volatile RecvBytes;
};

class MyClient
  : private tinySrv::NonCopyable
  , public tinySrv::IClient
{
  tinySrv::IClientCtrl *Ctrl;
  Statistics &Stat;
public:
  MyClient(Statistics &stat)
    : Ctrl(0)
    , Stat(stat)
  {
  }
  virtual bool Init(tinySrv::IClientCtrl *ctrl)
  {
    Stat.AddConnectCounter();
    Ctrl = ctrl;
    return true;
  }
  virtual void Done()
  {
    Stat.AddCloseCounter();
  }
  virtual void OnClose()
  {
  }
  virtual void OnData(void const *data, int bytes)
  {
    Stat.AddDataCounter(bytes);
    int SentBytes = bytes;
    for ( ; ; )
    {
      if (!Ctrl->SendData(data, &SentBytes))
      {
        Ctrl->CloseMe();
        std::cerr << "Failed to send data" << std::endl;
        break;
      }
      bytes -= SentBytes;
      if (!bytes)
        break;
      SentBytes = bytes;
    }
  }
};

class MyClientFactory
  : private tinySrv::NonCopyable
  , public tinySrv::IClientFactory
{
  Statistics &Stat;
public:
  MyClientFactory(Statistics &stat)
    : Stat(stat)
  {
  }
  virtual std::auto_ptr<tinySrv::IClient> CreateClinetItem()
  {
    return std::auto_ptr<tinySrv::IClient>(new MyClient(Stat));
  }
};

int main()
{
  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
  {
    std::cerr << "Can't set sigign" << std::endl;
    return 1;
  }  
  try
  {
    Statistics Stat;
    std::auto_ptr<tinySrv::ITCPServer> Server(tinySrv::CreateTCPServer());
    Server->Start("127.0.0.1", 5555, 5, 1000, 4,
      std::auto_ptr<tinySrv::IClientFactory>(new MyClientFactory(Stat)));
    std::cin.get();
    Stat.ShowStatistics();
  }
  catch (std::exception const &e)
  {
    std::cerr << "Error: " << e.what() << std::endl;
  }
  return 0;
}
